package com.zenithmind.library.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.common.result.Result;
import com.zenithmind.common.result.ResultCode;
import com.zenithmind.library.mapper.BookMapper;
import com.zenithmind.library.mapper.CategoryMapper;
import com.zenithmind.library.pojo.domain.Category;
import com.zenithmind.library.pojo.dto.CategoryCreateDTO;
import com.zenithmind.library.pojo.dto.CategoryUpdateDTO;
import com.zenithmind.library.pojo.query.CategoryQuery;
import com.zenithmind.library.pojo.vo.CategoryVO;
import com.zenithmind.library.service.CategoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 图书分类服务实现类
 * 
 * @author ZenithMind
 * @since 2024-06-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    private final CategoryMapper categoryMapper;
    private final BookMapper bookMapper;

    @Override
    @Cacheable(value = "categories", key = "'page:' + #query.hashCode()")
    public PageResult<CategoryVO> getCategoryPage(CategoryQuery query) {
        log.info("分页查询分类，查询条件：{}", query);

        Page<CategoryVO> page = query.toPage();
        IPage<CategoryVO> result = categoryMapper.selectCategoryPage(page, query);

        return PageResult.of(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    @Cacheable(value = "categories", key = "'tree:' + (#parentId != null ? #parentId : 'root')")
    public List<CategoryVO> getCategoryTree(String parentId) {
        log.info("获取分类树，父分类ID：{}", parentId);
        return categoryMapper.selectCategoryTree(parentId);
    }

    @Override
    @Cacheable(value = "categories", key = "'all_tree'")
    public List<CategoryVO> getAllCategoryTree() {
        log.info("获取所有分类树");
        return categoryMapper.selectAllCategoryTree();
    }

    @Override
    @Cacheable(value = "categories", key = "'detail:' + #id")
    public CategoryVO getCategoryDetail(String id) {
        log.info("查询分类详情，ID：{}", id);
        
        Category category = getById(id);
        if (category == null) {
            throw new RuntimeException("分类不存在");
        }
        
        return convertToVO(category);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "categories", allEntries = true)
    public Result<CategoryVO> createCategory(CategoryCreateDTO createDTO) {
        log.info("创建分类，数据：{}", createDTO);
        
        // 检查分类编码是否已存在
        if (existsByCode(createDTO.getCode(), null)) {
            return Result.fail(ResultCode.CONFLICT.getCode(), "分类编码已存在", null);
        }
        
        // 检查分类名称是否已存在
        if (existsByName(createDTO.getName(), createDTO.getParentId(), null)) {
            return Result.fail(ResultCode.CONFLICT.getCode(), "同级分类名称已存在", null);
        }
        
        // 转换为实体对象
        Category category = new Category();
        BeanUtils.copyProperties(createDTO, category);
        
        // 设置层级信息
        setCategoryLevel(category, createDTO.getParentId());
        
        category.setStatus(1); // 默认启用
        category.setCreateTime(LocalDateTime.now());
        category.setUpdateTime(LocalDateTime.now());
        
        // 保存分类
        boolean saved = save(category);
        if (!saved) {
            return Result.fail(ResultCode.FAIL.getCode(), "创建分类失败", null);
        }
        
        // 更新父分类的叶子节点状态
        updateParentLeafStatus(createDTO.getParentId());
        
        // 返回创建的分类信息
        CategoryVO categoryVO = convertToVO(category);
        return Result.success(categoryVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "categories", allEntries = true)
    public Result<CategoryVO> updateCategory(String id, CategoryUpdateDTO updateDTO) {
        log.info("更新分类，ID：{}，数据：{}", id, updateDTO);
        
        // 检查分类是否存在
        Category existingCategory = getById(id);
        if (existingCategory == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "分类不存在", null);
        }
        
        // 检查分类编码是否已被其他分类使用
        if (StringUtils.hasText(updateDTO.getCode()) && 
            existsByCode(updateDTO.getCode(), id)) {
            return Result.fail(ResultCode.CONFLICT.getCode(), "分类编码已被其他分类使用", null);
        }
        
        // 检查分类名称是否已被其他分类使用
        if (StringUtils.hasText(updateDTO.getName()) && 
            existsByName(updateDTO.getName(), updateDTO.getParentId(), id)) {
            return Result.fail(ResultCode.CONFLICT.getCode(), "同级分类名称已存在", null);
        }
        
        // 更新分类信息
        Category category = new Category();
        BeanUtils.copyProperties(updateDTO, category);
        category.setId(id);
        category.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(category);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新分类失败", null);
        }
        
        // 返回更新后的分类信息
        Category updatedCategory = getById(id);
        CategoryVO categoryVO = convertToVO(updatedCategory);
        return Result.success(categoryVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "categories", allEntries = true)
    public Result<Void> deleteCategory(String id) {
        log.info("删除分类，ID：{}", id);
        
        // 检查分类是否存在
        Category category = getById(id);
        if (category == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "分类不存在", null);
        }
        
        // 检查是否有图书关联
        Long bookCount = bookMapper.countBooksByCategory(id);
        if (bookCount != null && bookCount > 0) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "该分类下还有图书，无法删除", null);
        }
        
        // 检查是否有子分类
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getParentId, id);
        long subCategoryCount = count(wrapper);
        if (subCategoryCount > 0) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "该分类下还有子分类，无法删除", null);
        }
        
        // 删除分类
        boolean deleted = removeById(id);
        if (!deleted) {
            return Result.fail(ResultCode.FAIL.getCode(), "删除分类失败", null);
        }
        
        // 更新父分类的叶子节点状态
        updateParentLeafStatus(category.getParentId());
        
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "categories", allEntries = true)
    public Result<Void> batchDeleteCategories(List<String> ids) {
        log.info("批量删除分类，IDs：{}", ids);
        
        // 检查每个分类是否可以删除
        for (String id : ids) {
            Category category = getById(id);
            if (category == null) {
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "分类不存在：" + id, null);
            }
            
            int childrenCount = categoryMapper.countChildren(id);
            if (childrenCount > 0) {
                return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "分类《" + category.getName() + "》下还有子分类，无法删除", null);
            }
        }
        
        // 批量删除
        boolean deleted = removeByIds(ids);
        if (!deleted) {
            return Result.fail(ResultCode.FAIL.getCode(), "批量删除分类失败", null);
        }
        
        return Result.success();
    }

    @Override
    @CacheEvict(value = "categories", allEntries = true)
    public Result<Void> enableCategory(String id) {
        log.info("启用分类，ID：{}", id);
        return updateCategoryStatus(id, 1);
    }

    @Override
    @CacheEvict(value = "categories", allEntries = true)
    public Result<Void> disableCategory(String id) {
        log.info("禁用分类，ID：{}", id);
        return updateCategoryStatus(id, 0);
    }

    @Override
    @Cacheable(value = "categories", key = "'code:' + #code")
    public CategoryVO getCategoryByCode(String code) {
        log.info("根据编码查询分类，编码：{}", code);
        return categoryMapper.selectByCode(code);
    }

    @Override
    @Cacheable(value = "categories", key = "'children:' + #parentId")
    public List<CategoryVO> getChildren(String parentId) {
        log.info("获取子分类，父分类ID：{}", parentId);
        return categoryMapper.selectChildren(parentId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "categories", allEntries = true)
    public Result<Void> moveCategory(String id, String newParentId) {
        log.info("移动分类，ID：{}，新父分类ID：{}", id, newParentId);
        
        Category category = getById(id);
        if (category == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "分类不存在", null);
        }
        
        // 检查是否移动到自己的子分类下
        if (isDescendant(newParentId, id)) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "不能移动到自己的子分类下", null);
        }
        
        String oldParentId = category.getParentId();
        
        // 更新分类的父分类
        category.setParentId(newParentId);
        setCategoryLevel(category, newParentId);
        category.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(category);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "移动分类失败", null);
        }
        
        // 更新原父分类和新父分类的叶子节点状态
        updateParentLeafStatus(oldParentId);
        updateParentLeafStatus(newParentId);
        
        return Result.success();
    }

    @Override
    @CacheEvict(value = "categories", allEntries = true)
    public Result<Void> updateCategorySortOrder(String id, Integer sortOrder) {
        log.info("更新分类排序，ID：{}，排序号：{}", id, sortOrder);
        
        Category category = new Category();
        category.setId(id);
        category.setSortOrder(sortOrder);
        category.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(category);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新分类排序失败", null);
        }
        
        return Result.success();
    }

    @Override
    @Cacheable(value = "categories", key = "'hot:' + #limit")
    public List<CategoryVO> getHotCategories(Integer limit) {
        log.info("获取热门分类，限制数量：{}", limit);
        return categoryMapper.selectHotCategories(limit);
    }

    @Override
    @CacheEvict(value = "categories", allEntries = true)
    public Result<Void> updateCategoryBookCount(String categoryId) {
        log.info("更新分类图书数量，分类ID：{}", categoryId);
        
        // TODO: 实现图书数量统计逻辑
        // Long bookCount = bookMapper.countBooksByCategory(categoryId);
        // categoryMapper.updateBookCount(categoryId, bookCount);
        
        return Result.success();
    }

    @Override
    public boolean existsByCode(String code, String excludeId) {
        return categoryMapper.existsByCode(code, excludeId);
    }

    @Override
    public boolean existsByName(String name, String parentId, String excludeId) {
        return categoryMapper.existsByName(name, parentId, excludeId);
    }

    @Override
    public Result<String> importCategories(List<CategoryCreateDTO> categories) {
        log.info("导入分类数据，数量：{}", categories.size());
        
        // TODO: 实现批量导入逻辑
        return Result.success("导入成功");
    }

    @Override
    public Result<String> exportCategories(CategoryQuery query) {
        log.info("导出分类数据，查询条件：{}", query);
        
        // TODO: 实现数据导出逻辑
        return Result.success("/exports/categories_" + System.currentTimeMillis() + ".xlsx");
    }

    /**
     * 更新分类状态
     */
    private Result<Void> updateCategoryStatus(String id, Integer status) {
        Category category = new Category();
        category.setId(id);
        category.setStatus(status);
        category.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(category);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新分类状态失败", null);
        }
        
        return Result.success();
    }

    /**
     * 设置分类层级信息
     */
    private void setCategoryLevel(Category category, String parentId) {
        if (StringUtils.hasText(parentId) && !"0".equals(parentId)) {
            Category parent = getById(parentId);
            if (parent != null) {
                category.setLevel(parent.getLevel() + 1);
                category.setPath(parent.getPath() + "/" + category.getCode());
            }
        } else {
            category.setLevel(1);
            category.setPath("/" + category.getCode());
        }
        category.setIsLeaf(1); // 新创建的分类默认为叶子节点
    }

    /**
     * 更新父分类的叶子节点状态
     */
    private void updateParentLeafStatus(String parentId) {
        if (StringUtils.hasText(parentId) && !"0".equals(parentId)) {
            int childrenCount = categoryMapper.countChildren(parentId);
            int isLeaf = childrenCount > 0 ? 0 : 1;
            categoryMapper.updateCategoryLevel(parentId, null, null, isLeaf);
        }
    }

    /**
     * 检查是否为后代分类
     */
    private boolean isDescendant(String ancestorId, String descendantId) {
        if (!StringUtils.hasText(ancestorId) || "0".equals(ancestorId)) {
            return false;
        }
        
        Category ancestor = getById(ancestorId);
        Category descendant = getById(descendantId);
        
        if (ancestor == null || descendant == null) {
            return false;
        }
        
        return ancestor.getPath().startsWith(descendant.getPath());
    }

    /**
     * 转换为VO对象
     */
    private CategoryVO convertToVO(Category category) {
        CategoryVO categoryVO = new CategoryVO();
        BeanUtils.copyProperties(category, categoryVO);
        return categoryVO;
    }
}
